package j.framework.query.core;

import j.util.New;
import j.util.StringUtils;

import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 查询元数据
 * Created by junhai on 2015/1/3.
 */
public class QueryMetadata implements java.io.Serializable {

    /**
     * 主键列
     */
    private List<DataColumn> primaryKeys = New.list();

    /**
     * 默认排序列
     */
    private List<DataSortColumn> defaultQuerySort = New.list();

    /*
    查询每行上的操作集
     */
    private List<QueryAction> actions;
    private QueryFieldMetadata treeTableParentField;
    private QueryFieldMetadata treeTableField;

    public boolean hasActions() {
        return actions!=null && actions.size()>0;
    }
    public List<QueryAction> getActions(){
        return actions;
    }
    public void putAction(QueryAction action){
        if(actions == null){
            actions = New.list();
        }
        actions.add(action);
    }

    //生成后的footer语句，当前仅支持easyui
    private String footerClause;

    private List<QueryFieldFooter> footers;

    public void putFooter(QueryFieldFooter footer){
        if(footers == null){
            footers = New.list();
        }
        footers.add(footer);
    }

    public String getFooterClause() {
        if(footers == null || footers.size()==0){
            return null;
        }
        if(StringUtils.isNotEmpty(footerClause)){
            return footerClause;
        }
        synchronized (QueryMetadata.class){
            if(StringUtils.isNullOrEmpty(footerClause)){
                StringBuilder s = new StringBuilder();
                int i=0;
                String footerFieldName;
                QueryFieldMetadata qfmd;
                for(QueryFieldFooter footer : footers) {
                    qfmd = getFieldMetadata(footer.getQueryFieldId());
                    if (qfmd == null) {
                        continue;
                    }
                    if (i++ > 0) {
                        s.append(",");
                    }
                    footerFieldName = qfmd.getFieldName();
                    if (StringUtils.isNotEmpty(qfmd.getTableAliasName())) {
                        footerFieldName = qfmd.getTableAliasName() + "." + footerFieldName;
                    }
                    s.append(footer.getFunctionType()).append("(").append(footerFieldName).append(")");
                    s.append(" as ").append(qfmd.getFieldName());
                }
                footerClause = s.toString();
            }
        }
        return footerClause;
    }

    private Map<String,QueryFieldMetadata> fieldMetadataMap = New.lMap();
    private Map<String,String> fieldNameIdMapper = New.map();
    /**
     * 按多表头来处理数据列，每个列有子列，不限级
     */
    public final Map<String,DataGridColumn> columns = New.lMap();
    /**
     * 多表头的所有列，没有上下级之分，仅用来查找引用
     */
    public final Map<String,DataGridColumn> dataGridColumnMap = New.map();

    /**
     * 根据key获取数据列元数据，key可以是数据库表的字段名，也可以是主键ID
     * @param key
     * @return
     */
    public QueryFieldMetadata getFieldMetadata(String key){
        QueryFieldMetadata qfmd = fieldMetadataMap.get(key);
        if(qfmd == null){
            qfmd = fieldMetadataMap.get(fieldNameIdMapper.get(key));
        }
        return qfmd;
    }

    /**
     * 根据数据库中的字段名获取其定义的元数据
     * @param fieldName
     * @return
     */
    public QueryFieldMetadata getFieldMetadataByFieldName(String fieldName){
        String id = fieldNameIdMapper.get(fieldName);
        return fieldMetadataMap.get(id);
    }

    private boolean hasGroupColumns = false;
    private int groupDepth = 1;

    public boolean isHasGroupColumns() {
        return hasGroupColumns;
    }

    public int getGroupDepth() {
        return groupDepth;
    }

    /**
     * 增加列元数据，在增加的同时，根据是否有多表头处理表头的分类
     * @param md
     */
    public void putFieldMetadata(QueryFieldMetadata md){
        fieldMetadataMap.put(md.getQueryFieldId(),md);
        fieldNameIdMapper.put(md.getFieldName(),md.getQueryFieldId());
        if(this.isTreeTable()){
            if(md.isAsTreeParentField()){
                this.treeTableParentField = md;
            }
            if(md.isAsTreeField()){
                this.treeTableField = md;
            }
        }
        if(md.isPrimaryKey()){
            DataColumn dc = new DataColumn();
            dc.setDataColumnId(md.getQueryFieldId());
            dc.setTableAliasName(md.getTableAliasName());
            dc.setUsedFieldNameAsKey(md.isUsedFieldNameAsKey());
            dc.setColumnName(md.getFieldName());
            this.putPrimaryKey(dc);
        }
        if(md.isSuppressible()){
            //这列不显示(这是隐藏列)，直接不处理
            return;
        }
        if(md.isAsDefaultSort()){
            DataSortColumn dsColumn = new DataSortColumn(
                    md.isUsedFieldNameAsKey(),md.getQueryFieldId(),
                    md.getTableAliasName(),md.getFieldName()
            );
            dsColumn.setOrderBy(md.getDefaultSortOrder());
            defaultQuerySort.add(dsColumn);
        }
        DataGridColumn dgColumn = new DataGridColumn();
        dgColumn.setTitle(md.getDisplayName());
        dgColumn.setFieldKey(md.getQueryFieldId());
        dgColumn.setDisplayOrder(md.getDisplayOrder());
        String[] tags;
        if(StringUtils.isNotEmpty(md.getDisplayNameTag())){
            //这是多表头
            if(!hasGroupColumns){
                hasGroupColumns = true;
            }
            tags = md.getDisplayNameTag().split("\\|");
            if(tags.length >= groupDepth){
                groupDepth  = tags.length+1;
            }
            DataGridColumn columnByTag = null;
            DataGridColumn lastTag = null;
            for(String tag : tags){
                columnByTag = dataGridColumnMap.get(tag);
                if(columnByTag==null){
                    columnByTag = new DataGridColumn();
                    columnByTag.setTitle(tag);
                    columnByTag.setDisplayOrder(md.getDisplayOrder());
                    columnByTag.setSuperHeader(true);
                    if(lastTag == null){
                        columns.put(columnByTag.getTitle(),columnByTag);
                    }else{
                        lastTag.subColumns.put(tag,columnByTag);
                    }
                    dataGridColumnMap.put(columnByTag.getTitle(),columnByTag);
                }
                lastTag = columnByTag;
            }
            if(columnByTag!=null){
                columnByTag.subColumns.put(dgColumn.getTitle(),dgColumn);
            }
        }else{
            //没有多表头
            columns.put(dgColumn.getTitle(),dgColumn);
        }
    }

    public Collection<QueryFieldMetadata> getFieldMetadataList(){
        return fieldMetadataMap.values();
    }

    /**
     * 获取默认的排序语句
     * 在构造easyui的table标签时用到
     * @return
     */
    public String getDefaultSortNames(){
        if(defaultQuerySort.size()==0){
            return "";
        }
        StringBuilder s = new StringBuilder();
        for(DataSortColumn sort : defaultQuerySort){
            s.append(sort.getFieldKey()).append(",");
        }
        s.deleteCharAt(s.length()-1);
        return s.toString();
    }

    /**
     * 获取默认的排序顺序
     * 在构造easyui的table标签时用到
     * @return
     */
    public String getDefaultOrders(){
        if(defaultQuerySort.size()==0){
            return "";
        }
        StringBuilder s = new StringBuilder();
        for(DataSortColumn sort : defaultQuerySort){
            s.append(sort.getOrderBy().toLowerCase()).append(",");
        }
        s.deleteCharAt(s.length()-1);
        return s.toString();
    }

    public List<DataColumn> getPrimaryKeys() {
        return primaryKeys;
    }
    public void putPrimaryKey(DataColumn dataColumn) {
        this.primaryKeys.add(dataColumn);
    }

    public List<DataSortColumn> getDefaultQuerySort() {
        return defaultQuerySort;
    }
    public void setDefaultQuerySort(List<DataSortColumn> defaultQuerySort) {
        this.defaultQuerySort = defaultQuerySort;
    }

    private String queryId;

    private boolean checkFunctionPrivilege;//是否检测模块权限

    private String functionId;//若检测模块权限，则每次请求时，则检查当前登录用户是否具备此模块权限

    private String queryKey;//若指定，可与queryId二选其一做为key来引用此查询

    private String name;

    private String querySql;

    private boolean isNamedSql;//此查询的sql语句是否基于参数为指定名字的

    private boolean isProcedure;//是否为存储过程，若是，则namedSql一定为named

    private Integer actionsColumnWidth;//操作列宽度

    private String beanClassName;

    private String buildWhereMethodName;//必须有beanId方可用

    private boolean pagingSupported;
    private Integer pageSize;
    private String pageList;//逗号隔开的数字列表

    private boolean footerSupported;

    private boolean multiColumnSortedSupported;

    private boolean singleSelect = true;//默认为单选

    private boolean isTreeTable;//是否为树表显示

    //是否显示行号
    private boolean showRowNumber;//是否显示行号

    private Integer frozenLeftColumns;//左冻结列数

    private Integer frozenTopRows;//上冻结行数

    public String getQueryId() {
        return queryId;
    }
    public void setQueryId(String queryId) {
        this.queryId = queryId;
    }

    public boolean isCheckFunctionPrivilege() {
        return checkFunctionPrivilege;
    }
    public void setCheckFunctionPrivilege(boolean checkFunctionPrivilege) {
        this.checkFunctionPrivilege = checkFunctionPrivilege;
    }

    public String getFunctionId() {
        return functionId;
    }
    public void setFunctionId(String functionId) {
        this.functionId = functionId;
    }

    public String getQueryKey() {
        return queryKey;
    }
    public void setQueryKey(String queryKey) {
        this.queryKey = queryKey;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public String getQuerySql() {
        return querySql;
    }
    public void setQuerySql(String querySql) {
        this.querySql = querySql;
    }

    public boolean isNamedSql() {
        return isNamedSql;
    }
    public void setNamedSql(boolean isNamedSql) {
        this.isNamedSql = isNamedSql;
    }

    public boolean isProcedure() {
        return isProcedure;
    }
    public void setProcedure(boolean isProcedure) {
        this.isProcedure = isProcedure;
    }

    public void setActionsColumnWidth(Integer actionsColumnWidth) {
        this.actionsColumnWidth = actionsColumnWidth;
    }
    public Integer getActionsColumnWidth() {
        return actionsColumnWidth;
    }

    public String getBeanClassName() {
        return beanClassName;
    }
    public void setBeanClassName(String beanClassName) {
        this.beanClassName = beanClassName;
    }

    public String getBuildWhereMethodName() {
        return buildWhereMethodName;
    }
    public void setBuildWhereMethodName(String buildWhereMethodName) {
        this.buildWhereMethodName = buildWhereMethodName;
    }

    public boolean isPagingSupported() {
        return pagingSupported;
    }
    public void setPagingSupported(boolean pagingSupported) {
        this.pagingSupported = pagingSupported;
    }

    public Integer getPageSize() {
        return pageSize;
    }
    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }

    public String getPageList() {
        return pageList;
    }
    public void setPageList(String pageList) {
        this.pageList = pageList;
    }

    public boolean isFooterSupported() {
        return footerSupported;
    }
    public void setFooterSupported(boolean footerSupported) {
        this.footerSupported = footerSupported;
    }

    public boolean isMultiColumnSortedSupported() {
        return multiColumnSortedSupported;
    }
    public void setMultiColumnSortedSupported(boolean multiColumnSortedSupported) {
        this.multiColumnSortedSupported = multiColumnSortedSupported;
    }

    public boolean isSingleSelect() {
        return singleSelect;
    }
    public void setSingleSelect(boolean singleSelect) {
        this.singleSelect = singleSelect;
    }

    public boolean isTreeTable() {
        return isTreeTable;
    }
    public void setTreeTable(boolean isTreeTable) {
        this.isTreeTable = isTreeTable;
    }

    public boolean isShowRowNumber() {
        return showRowNumber;
    }
    public void setShowRowNumber(boolean showRowNumber) {
        this.showRowNumber = showRowNumber;
    }

    public Integer getFrozenLeftColumns() {
        return frozenLeftColumns;
    }
    public void setFrozenLeftColumns(Integer frozenLeftColumns) {
        this.frozenLeftColumns = frozenLeftColumns;
    }

    public Integer getFrozenTopRows() {
        return frozenTopRows;
    }
    public void setFrozenTopRows(Integer frozenTopRows) {
        this.frozenTopRows = frozenTopRows;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        QueryMetadata that = (QueryMetadata) o;

        if (queryId != null ? !queryId.equals(that.queryId) : that.queryId != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return queryId != null ? queryId.hashCode() : 0;
    }

    public Map<String, DataGridColumn> getColumns() {
        return columns;
    }

    public String buildQueryOrder(String sort,String order){
        int j=0;
        StringBuilder sqlOrder = new StringBuilder();
        if(StringUtils.isNotEmpty(sort)){
            if(StringUtils.isNullOrEmpty(order)){
                order = "asc";
            }
            String[] orderArr = order.split(",");
            String[] sortColumns = sort.split(",");
            QueryFieldMetadata queryFieldMetadata;
            for(int i=0;i<sortColumns.length;i++){
                queryFieldMetadata = getFieldMetadata(sortColumns[i]);
                if(queryFieldMetadata!=null){
                    if(j++>0){
                        sqlOrder.append(",");
                    }
                    if(StringUtils.isNotEmpty(queryFieldMetadata.getTableAliasName())){
                        sqlOrder.append(queryFieldMetadata.getTableAliasName()).append(".");
                    }
                    sqlOrder.append(queryFieldMetadata.getFieldName());
                    order = null;
                    if(i<orderArr.length){
                        order = orderArr[i];
                    }
                    if(StringUtils.isNullOrEmpty(order)){
                        order = "asc";
                    }
                    sqlOrder.append(" ").append(order);
                }
            }
        }else if(getDefaultQuerySort()!=null && getDefaultQuerySort().size()>0){
            //根据默认排序列排序
            for(DataSortColumn dsc : getDefaultQuerySort()){
                if(j++>0){
                    sqlOrder.append(",");
                }
                sqlOrder.append(dsc.getColumnName()).append(" ").append(dsc.getOrderBy());
            }
        }
        if(j>0){
            return " order by "+sqlOrder.toString();
        }
        return null;
    }

    public String getTreeTableFieldName(){
        if(this.treeTableField != null){
            if(this.treeTableField.isUsedFieldNameAsKey()){
                return this.treeTableField.getFieldName();
            }
            return this.treeTableField.getQueryFieldId();
        }
        return "";
    }

    public String getTreeTableIdFieldName(){
        if(primaryKeys.size()>0){
            DataColumn dc = primaryKeys.get(0);
            return dc.getFieldKey();
        }
        return "";
    }

    public String getTreeTableParentFieldName() {
        if(treeTableParentField != null){
            return treeTableParentField.getFieldName();
        }
        return "";
    }
}
